package com.uinnova.product.eam.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.binary.core.exception.BinaryException;
import com.binary.core.util.BinaryUtils;
import com.binary.jdbc.Page;
import com.uinnova.product.eam.comm.diagram.DiagramReviewInfo;
import com.uinnova.product.eam.comm.diagram.DiagramReviewState;
import com.uinnova.product.eam.constant.ArchReviewFlowType;
import com.uinnova.product.eam.constant.ArchReviewRangeStage;
import com.uinnova.product.eam.constant.ArchReviewState;
import com.uinnova.product.eam.constant.ItemType;
import com.uinnova.product.eam.dto.SimpProjectInfo;
import com.uinnova.product.eam.dto.SimpSystemInfo;
import com.uinnova.product.eam.feign.workable.FlowableFeign;
import com.uinnova.product.eam.feign.workable.entity.AllDiagramInstanceDto;
import com.uinnova.product.eam.feign.workable.entity.ArchReviewTaskQueryReq;
import com.uinnova.product.eam.feign.workable.entity.DiagramReviewTaskQueryReq;
import com.uinnova.product.eam.feign.workable.entity.TaskResponse;
import com.uinnova.product.eam.model.EamArtifactVo;
import com.uinnova.product.eam.model.es.ArchReviewInfo;
import com.uinnova.product.eam.service.DiagramReviewInfoSvc;
import com.uinnova.product.eam.service.EamCategorySvc;
import com.uinnova.product.eam.service.IEamArtifactSvc;
import com.uinnova.product.eam.service.es.DiagramReviewInfoDao;
import com.uinnova.product.eam.service.exception.BusinessException;
import com.uinnova.product.eam.vo.*;
import com.uinnova.project.base.diagram.comm.model.ESDiagram;
import com.uinnova.project.service.eam.ESDiagramSvc;
import com.uino.api.client.permission.IUserApiSvc;
import com.uino.bean.permission.base.SysOrg;
import com.uino.bean.permission.base.SysUser;
import com.uino.bean.permission.business.UserInfo;
import com.uino.dao.permission.ESUserSvc;
import com.uino.dao.util.ESUtil;
import com.uino.service.permission.microservice.IUserSvc;
import com.uino.util.sys.SysUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class DiagramReviewInfoImpl implements DiagramReviewInfoSvc {
    private static final SimpleDateFormat STR_DF = new SimpleDateFormat("yyyy-MM-dd");

    @Autowired
    private FlowableFeign flowableFeign;
    @Autowired
    private DiagramReviewInfoDao diagramReviewInfoDao;
    @Resource
    private ESDiagramSvc esDiagramSvc;
    @Autowired
    IEamArtifactSvc eamArtifactSvc;
    @Autowired
    private ESUserSvc esUserSvc;
    @Autowired
    private IUserSvc userSvc;

    public Page<DiagramReviewRes> page(DiagramReviewQueryReq req){
        QueryBuilder query = getQuery(req);
        List<SortBuilder<?>> sorts = new ArrayList<>();
        FieldSortBuilder createTimeSort = SortBuilders.fieldSort("createTime").order(SortOrder.DESC);
        sorts.add(createTimeSort);
        Page<DiagramReviewInfo> page = diagramReviewInfoDao.getSortListByQuery(req.getPageNum(), req.getPageSize(), query, sorts);
        if (CollectionUtils.isEmpty(page.getData())) {
            return new Page<>(req.getPageNum(), req.getPageSize(), 0, 0, new ArrayList<>());
        }
        List<String> activeProcessInstanceIds = new ArrayList<>();
        for (DiagramReviewInfo diagramReviewInfo : page.getData()) {
            if (StringUtils.isNotBlank(diagramReviewInfo.getProcessInstanceId())
                    && DiagramReviewState.REVIEWING.equals(diagramReviewInfo.getState())) {
                activeProcessInstanceIds.add(diagramReviewInfo.getProcessInstanceId());
            }
        }
        Map<String, List<TaskResponse>> activeTaskMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(activeProcessInstanceIds)) {
            List<TaskResponse> tasks = flowableFeign.getActiveSimpleTaskByProcessInstanceIds(activeProcessInstanceIds);
            if (!CollectionUtils.isEmpty(tasks)) {
                tasks.sort(Comparator.comparing(TaskResponse::getTaskCreateTime));
                activeTaskMap = tasks.stream().collect(Collectors.groupingBy(TaskResponse::getProcessInstanceId));
            }
        }
        List<DiagramReviewRes> resultList = new ArrayList<>();
        for (DiagramReviewInfo datum : page.getData()) {
            DiagramReviewRes diagramReviewRes = BeanUtil.copyProperties(datum, DiagramReviewRes.class);
            //当前节点
            String stage = "-";
            if (StringUtils.isNotBlank(datum.getProcessInstanceId()) &&
                    activeTaskMap.containsKey(datum.getProcessInstanceId())) {
                List<TaskResponse> tasks = activeTaskMap.get(datum.getProcessInstanceId());
                List<String> names = new ArrayList<>();
                for (TaskResponse task : tasks) {
                    String name = task.getTaskName();
                    if (StringUtils.isNotBlank(name) && !names.contains(name)) {
                        names.add(name);
                    }
                }
                if (!CollectionUtils.isEmpty(names)) {
                    stage = String.join(",", names);
                }
            }
            diagramReviewRes.setStage(stage);
            diagramReviewRes.setCreateTime(transDateFormat(datum.getCreateTime(), "yyyy-MM-dd"));
            diagramReviewRes.setProcessFinishTimeFormat(transDateFormat(datum.getProcessFinishTime(), "yyyy-MM-dd"));
            resultList.add(diagramReviewRes);
        }

        return new Page<>(req.getPageNum(), req.getPageSize(), page.getTotalRows(), page.getTotalPages(), resultList);
    }
    private String transDateFormat(Long date, String format) {
        if (date == null) {
            return "-";
        }
        SimpleDateFormat timeFormatter = new SimpleDateFormat("yyyyMMddHHmmss");
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try {
            return sdf.format(timeFormatter.parse(date.toString()));
        } catch (ParseException e) {
            log.error("时间格式转化失败:date:{},format:{}", date, format);
        }
        return "-";
    }

    private QueryBuilder getQuery(DiagramReviewQueryReq req) {
        Assert.notNull(req, "分页参数不能为空");
        Assert.notNull(req.getPageNum(), "第几页不能为空");
        Assert.notNull(req.getPageSize(), "每页显示记录数不能为空");
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        if (StringUtils.isNotBlank(req.getReviewOrDiagramName())) {
            // 根据评审名称或者视图名称查询
            BoolQueryBuilder nameOrQuery = QueryBuilders.boolQuery();
            nameOrQuery.should(QueryBuilders.wildcardQuery("reviewName.keyword", "*" + req.getReviewOrDiagramName().trim() + "*"));
            nameOrQuery.should(QueryBuilders.wildcardQuery("diagramName.keyword", "*" + req.getReviewOrDiagramName().trim() + "*"));
            query.must(nameOrQuery);
        }
        List<String> submitOrgIdList = req.getSubmitOrgId();
        if (!CollectionUtils.isEmpty(submitOrgIdList)) {
            query.must(QueryBuilders.termsQuery("creatorOrgIdList", submitOrgIdList));
        }
        if (StringUtils.isNotBlank(req.getCreateTimeBegin()) || StringUtils.isNotBlank(req.getCreateTimeEnd())) {
            RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("createTime");
            if (StringUtils.isNotBlank(req.getCreateTimeBegin())) {
                Long timeBeginLong = ESUtil.getNumberDateTime(getDate(req.getCreateTimeBegin()));
                rangeQuery.gte(timeBeginLong);
            }
            if (StringUtils.isNotBlank(req.getCreateTimeEnd())) {
                Long timeEndLong = ESUtil.getNumberDateTime(getDate(req.getCreateTimeEnd()));
                rangeQuery.lte(timeEndLong);
            }
            query.must(rangeQuery);
        }
        if (req.getState() != null) {
            query.must(QueryBuilders.termQuery("state.keyword", req.getState()));
        }
        if (StringUtils.isNotBlank(req.getStage())) {
            DiagramReviewTaskQueryReq diagramReviewTaskQueryReq = new DiagramReviewTaskQueryReq();
            diagramReviewTaskQueryReq.setType(1);
            diagramReviewTaskQueryReq.setStages(Arrays.asList(req.getStage()));
            List<TaskResponse> tasks = flowableFeign.listForDiagram(diagramReviewTaskQueryReq);
            if (CollectionUtils.isEmpty(tasks)) {
                return QueryBuilders.termQuery("id", -1);
            }
            Set<String> processInstanceIds = tasks.stream().map(TaskResponse::getProcessInstanceId).filter(Objects::nonNull).collect(Collectors.toSet());
            if (CollectionUtils.isEmpty(processInstanceIds)) {
                return QueryBuilders.termQuery("id", -1);
            }
            query.must(QueryBuilders.termsQuery("processInstanceId.keyword", processInstanceIds));
        }
        if (req.getFlowType() != null) {
            String curUserLoginCode = SysUtil.getCurrentUserInfo().getLoginCode();
            if (ArchReviewFlowType.START_BY_ME.equals(req.getFlowType())) {
                query.must(QueryBuilders.termQuery("creatorCode.keyword", curUserLoginCode));
            }
            if (ArchReviewFlowType.TO_DO.equals(req.getFlowType())
                    || ArchReviewFlowType.DONE.equals(req.getFlowType())) {
                DiagramReviewTaskQueryReq diagramReviewTaskQueryReq = new DiagramReviewTaskQueryReq();
                diagramReviewTaskQueryReq.setType(ArchReviewFlowType.TO_DO.equals(req.getFlowType()) ? 2 : 3);
                diagramReviewTaskQueryReq.setAssignee(curUserLoginCode);
                List<TaskResponse> tasks = flowableFeign.listForDiagram(diagramReviewTaskQueryReq);
                if (CollectionUtils.isEmpty(tasks)) {
                    return QueryBuilders.termQuery("id", -1);
                }
                Set<String> processInstanceIds = tasks.stream().map(TaskResponse::getProcessInstanceId).filter(Objects::nonNull).collect(Collectors.toSet());
                if (CollectionUtils.isEmpty(processInstanceIds)) {
                    return QueryBuilders.termQuery("id", -1);
                }
                query.must(QueryBuilders.termsQuery("processInstanceId.keyword", processInstanceIds));
            }
        }
        return query;
    }

    private Date getDate(String dateStr) {
        try {
            return STR_DF.parse(dateStr);
        } catch (ParseException e) {
            throw new BinaryException("日期转换错误:" + dateStr);
        }
    }

    public void getAllDiagramProcess(){
        //查询所有视图流程
        List<AllDiagramInstanceDto> allDiagramInstance = flowableFeign.getAllDiagramInstance();
        List<DiagramReviewInfo> diagramReviewInfoList = new ArrayList<>();
        for (AllDiagramInstanceDto allDiagramInstanceDto : allDiagramInstance) {
            // 流程发起人
            BoolQueryBuilder must = QueryBuilders.boolQuery().must(QueryBuilders.termQuery("loginCode.keyword", allDiagramInstanceDto.getStartUserId()));
            List<SysUser> listByQuery = esUserSvc.getListByQuery(must);
            if (CollectionUtils.isEmpty(listByQuery)) {
                log.info("用户不存在：{}", allDiagramInstanceDto.getStartUserId());
                continue;
            }
            UserInfo userInfo = userSvc.getUserInfoByLoginCode(allDiagramInstanceDto.getStartUserId());
            DiagramReviewInfo diagramReviewInfo = new DiagramReviewInfo();
            diagramReviewInfo.setId(ESUtil.getUUID());
            if (allDiagramInstanceDto.getStartTime() != null) {
                diagramReviewInfo.setCreateTime(ESUtil.getNumberDateTime(allDiagramInstanceDto.getStartTime()));
            }
            diagramReviewInfo.setReviewName(allDiagramInstanceDto.getProcessName());
            String businessKey = allDiagramInstanceDto.getBusinessKey();
            List<ESDiagram> diagramList = esDiagramSvc.queryDBDiagramInfoByIds(new String[]{businessKey});
            if (CollectionUtils.isEmpty(diagramList)) {
                log.info("根据businessKey：{},未能查询到视图", businessKey);
                continue;
            }
            ESDiagram esDiagram = diagramList.get(0);

            // 制品类型
            String viewTypeName = "-";
            if (esDiagram.getViewType() != null) {
                Long artifactId = Long.valueOf(esDiagram.getViewType());
                EamArtifactVo eamArtifactVo = eamArtifactSvc.queryArtifact(artifactId);
                if (eamArtifactVo != null) {
                    viewTypeName = eamArtifactVo.getArtifactName();
                }
            }
            List<String> submitterOrgName = new ArrayList<>();
            List<Long> submitterOrgId = new ArrayList<>();
            if (!org.apache.commons.collections4.CollectionUtils.isEmpty(userInfo.getOrgs())) {
                List<SysOrg> orgs = new ArrayList<>(userInfo.getOrgs());
                Iterator<SysOrg> iterator = orgs.iterator();
                while (iterator.hasNext()) {
                    SysOrg org = iterator.next();
                    submitterOrgName.add(org.getOrgAllLevelName());
                    submitterOrgId.add(org.getId());
                }
            }
            diagramReviewInfo.setDiagramId(esDiagram.getId());
            diagramReviewInfo.setDiagramEnergy(esDiagram.getDEnergy());
            diagramReviewInfo.setDiagramName(esDiagram.getName());
            diagramReviewInfo.setViewTypeName(viewTypeName);
            if ("REVIEWING".equals(allDiagramInstanceDto.getState())) {
                diagramReviewInfo.setState(DiagramReviewState.REVIEWING);
            }else if("PASS".equals(allDiagramInstanceDto.getState())){
                diagramReviewInfo.setState(DiagramReviewState.PASS);
            }else {
                diagramReviewInfo.setState(DiagramReviewState.TERM);
            }
            diagramReviewInfo.setCreatorCode(userInfo.getLoginCode());
            diagramReviewInfo.setCreatorName(userInfo.getUserName());
            diagramReviewInfo.setModifierCode(userInfo.getLoginCode());
            diagramReviewInfo.setModifierName(userInfo.getUserName());
            diagramReviewInfo.setModifyTime(ESUtil.getNumberDateTime());
            diagramReviewInfo.setCreatorOrgNameList(submitterOrgName);
            diagramReviewInfo.setCreatorOrgIdList(submitterOrgId);
            diagramReviewInfo.setProcessInstanceId(allDiagramInstanceDto.getProcessInstanceId());
            if (allDiagramInstanceDto.getEndTime() != null) {
                diagramReviewInfo.setProcessFinishTime(ESUtil.getNumberDateTime(allDiagramInstanceDto.getEndTime()));
            }
            diagramReviewInfoList.add(diagramReviewInfo);
        }
        if (!CollectionUtils.isEmpty(diagramReviewInfoList)) {
            diagramReviewInfoDao.saveOrUpdateBatch(diagramReviewInfoList);
        }
    }

}
